#ifndef __AIMAGE_H__
#define __AIMAGE_H__

#include <vector>
using namespace std;

#include "apixel.h"

class AVECTOR
{
	public:

	AVECTOR( const APIXEL &src );
	AVECTOR( void );
	AVECTOR( int );
	AVECTOR operator +( const AVECTOR &a);
	AVECTOR operator -( const AVECTOR &a);
	AVECTOR operator *( float f );
	float mag( void );
	void normalize( void );

	float x,y,z,w;
};

class AFLOOD_DATA
{
	public:

	AFLOOD_DATA( void )
	{
		num_pixels = 0;
		fill_to_border_mode = false;
		debug_xonly = false;
	}

	bool flood_test( APIXEL &curp )
	{
		if ( fill_to_border_mode )
		{
			if (	curp.r == rs &&
					curp.g == gs &&
					curp.b == bs )
			{
				return true;
			}
		}
		else
		{
			if (	curp.r != rs ||
					curp.g != gs ||
					curp.b != bs )
			{
				return true;
			}
		}
		return false;
	}

	void flood_update( int x, int y, APIXEL &curp )
	{
		num_pixels++;
		xc += x;
		yc += y;
		curp.r = rd;
		curp.g = gd;
		curp.b = bd;
	}

	int rs, gs, bs;
	int rd, gd, bd;
	int xl, yl, xh, yh;
	int xc, yc;
	int num_pixels;
	bool fill_to_border_mode;
	bool debug_xonly;
};

class ASTAR_DATA
{
	public:

	int pixels;
	float xc, yc;
	float minrad, maxrad;
	float goodness;
};

class ASTAR_GAIN
{
	public:
	int src, dst;
	float dist;
};

class ASTAR_TRANSFORM
{
	public:
	ASTAR_TRANSFORM( void ) { xo = 0.0f; yo = 0.0f; angle = 0.0f; }
	float xo, yo;
	float angle;
};

class AIMAGE;

class ASTAR_FIELD
{
	static const int max_stars = 4096;
	ASTAR_DATA stars[ max_stars ];
	int num_stars;

	public:
	int mapping_function[ max_stars ];

	ASTAR_FIELD( void ) { num_stars = 0; }
	void set_star( int num, const ASTAR_DATA &data );
	const ASTAR_DATA &get_star( int num ) const;
	int get_max_stars( void ) const { return max_stars; }
	int get_num_stars( void ) const { return num_stars; }
	void reverse_map( const ASTAR_FIELD &map );

	float get_ratio( void );
	void compute_goodness( const AIMAGE &congestion_map, float cong_weight );
	void filter_by_pixels( int num_pixels, bool filter_larger = false );
	void filter_by_distortion( float ratio );
	void filter_out_unmapped( void );
	void map_to( const ASTAR_FIELD &other_field );
	void top_x_by_pixels( int x );
	void top_x_by_goodness( int x );
	float get_score( void );
	float avg_distance( const ASTAR_FIELD &other_field, const ASTAR_TRANSFORM &transform );
	void recompute_map( const ASTAR_FIELD &other_field, const ASTAR_TRANSFORM &transform );
	void transform( const ASTAR_FIELD &other_field, const ASTAR_TRANSFORM &transform );
	ASTAR_TRANSFORM synch_fields( const ASTAR_FIELD &other_field, ASTAR_TRANSFORM t );
};

class ALINECALLBACK
{
	public:
	virtual void setpixel( int x, int y, float t, APIXEL &p ) = 0;
};

#define NUM_CIRCLE_SAMPLES 64

#define BUFSIZE 256

class SOLAR_FRAME_ALIGNMENT 
{
	public:

	char filename[ BUFSIZE ];
	float center_x;
	float center_y;
	float radius;
};

class SOLAR_FRAMES_ALIGNMENT 
{
	public:

	void read_solar_align_data( const char *filename );
	void lookup_alignment( const char *image, float &x, float &y, float &r );

	private:

	vector<SOLAR_FRAME_ALIGNMENT> frames;
};

class AERROR_SAMPLE
{
	public:
	bool m_sample_found;
	float m_error;
};

const int congestion_scale = 100;

class AIMAGE
{
	int m_height;
	int m_width;
	APIXEL **m_image;

	public:

	class iterator
	{

		public:
		APIXEL *p;

		bool operator !=( const iterator &a ) { return p != a.p; }
		bool operator ==( const iterator &a ) { return p == a.p; }
		APIXEL &operator *(void) { return *p; }
		iterator &operator ++( void  ) { p++; return *this; }
		iterator operator +( int i ) { iterator np; np.p = p+i; return np; }
		iterator operator -( int i ) { iterator np; np.p = p-i; return np; }
		iterator &operator +=( int i ) { p+=i; return *this; }
	};

	class const_iterator
	{

		public:
		APIXEL *p;

		bool operator !=( const const_iterator &a ) { return p != a.p; }
		bool operator ==( const const_iterator &a ) { return p == a.p; }
		const APIXEL &operator *(void) { return *p; }
		const_iterator &operator ++( void  ) { p++; return *this; }
		const_iterator operator +( int i ) { const_iterator np; np.p = p+i; return np; }
		const_iterator operator -( int i ) { const_iterator np; np.p = p-i; return np; }
		const_iterator &operator +=( int i ) { p+=i; return *this; }
	};


	AIMAGE( void );
	~AIMAGE( void );

	void alloc_image( int width, int height );
	void get_dim( int &width, int &height ) const;
	void free_image( void );

	iterator begin( void );
	iterator end( void );
	const_iterator const_begin( void ) const;
	const_iterator const_end( void ) const;

	void view();
	void do_edge( const AIMAGE &src );
	void colrange( float low, float hi );
	void scale_by_256();
	void hueshift( float gamma );

	void setpixel( int x, int y, APIXEL p);
	void getpixel( int x, int y, APIXEL &p) const;
	void raisepixel( int x, int y, const APIXEL &p);
	void adjust_by_alpha( const AIMAGE &alpha );
	void line( float x0, float y0, float x1, float y1, APIXEL p, bool smooth= true );
	void circle( float x0, float y0, float rad, APIXEL p, bool smooth = true );
	void line_callback( float x0, float y0, float x1, float y1, ALINECALLBACK &cb );
	void circlefind( float &xs, float &ys, float &rs, float &error );
	void scorecircle( float x, float y, float xr, float yr, AERROR_SAMPLE samples[ NUM_CIRCLE_SAMPLES ] );
	void copy( const AIMAGE &src, int xs, int ys, int xw, int yw, int xd, int yd );
	void makemask( float cutoff );
	void floodfill( int x, int y, AFLOOD_DATA &data, int count = 0 );
	int starfind( float cutoff, ASTAR_FIELD &stars );
	void mask_for_sunspots( const AIMAGE &src_image, float cutoff, int edge_span );
	void blueshift( int b );
	void redshift( int r );
	void drawstars( ASTAR_FIELD &stars, APIXEL tint );
	void make_congestion_map( const AIMAGE &src, const ASTAR_FIELD &stars, bool border_only );

	void rotate_and_add( AIMAGE &alpha, const AIMAGE &frame, ASTAR_TRANSFORM t );
	void diff( const AIMAGE &other );
	void add( const AIMAGE &img );
};

APIXEL blend_colors( APIXEL c0, APIXEL c1 );

#endif

